import PlayerCtrl from "../player/PlayerCtrl";
import { gameScene } from "../view/scene/GameScene";
import { mainCamera } from "../view/scene/MainCamera";

const { ccclass, property } = cc._decorator;

@ccclass
export default class Joystick extends cc.Component {

    @property({ displayName: "父节点", tooltip: "摇杆中心点和背景的父节点，需要用这个节点来做坐标转换", type: cc.Node })
    parent: cc.Node = null!;



    @property({ displayName: "摇杆背景", tooltip: "摇杆背景", type: cc.Node })
    bg: cc.Node = null!;

    @property({ displayName: "摇杆中心点", tooltip: "摇杆中心点", type: cc.Node })
    joystick: cc.Node = null!;
    @property({ displayName: "角色节点", tooltip: "角色节点", type: PlayerCtrl })
    heroCtrl: PlayerCtrl = null!;

    @property({ displayName: "最大半径", tooltip: "摇杆移动的最大半径", type: cc.Float })
    max_R: number = 200;

    @property({ displayName: "是否禁用摇杆", tooltip: "是否禁用摇杆，禁用后摇杆将不能摇动" })
    is_forbidden: boolean = false;


    // 角色旋转的角度，不要轻易修改
    angle: number = 0;

    // 移动向量
    vector: cc.Vec2 = new cc.Vec2(0, 0);
    _maxHeight: number = 1440;
    _maxWidth: number = 2560;

    _firstTouch: boolean = true;
    onLoad() {
        // 绑定事件
        // 因为摇杆中心点很小，如果给摇杆中心点绑定事件玩家将很难控制，摇杆的背景比较大，所以把事件都绑定在背景上是不错的选择，这样体验更好
        
        // 手指移动
        this.bg.on(cc.Node.EventType.TOUCH_MOVE, this.move, this);
        // 手指结束
        this.bg.on(cc.Node.EventType.TOUCH_END, this.finish, this);
        // 手指取消
        this.bg.on(cc.Node.EventType.TOUCH_CANCEL, this.finish, this);
        // this.node.opacity = 0;

        cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
        cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, this.onKeyUp, this);
    }

    protected start(): void {

        this.bg['_touchListener'].setSwallowTouches(false);
    }

    protected onDestroy(): void {
        mainCamera.node.setPosition(0, 0);
        // 手指移动
        this.bg.off(cc.Node.EventType.TOUCH_MOVE, this.move, this);
        // 手指结束
        this.bg.off(cc.Node.EventType.TOUCH_END, this.finish, this);
        // 手指取消
        this.bg.off(cc.Node.EventType.TOUCH_CANCEL, this.finish, this);
        // this.node.opacity = 0;
        cc.systemEvent.off(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
        cc.systemEvent.off(cc.SystemEvent.EventType.KEY_UP, this.onKeyUp, this);
    }

    onKeyDown(event) {
        switch (event.keyCode) {
            case cc.macro.KEY.w:
                this.vector.y = 100;
                break;
            case cc.macro.KEY.s:
                this.vector.y = -100;
                break;
            case cc.macro.KEY.a:
                this.vector.x = -100;
                break;
            case cc.macro.KEY.d:
                this.vector.x = 100;
                break;
        }
    }

    onKeyUp(event) {
        switch (event.keyCode) {
            case cc.macro.KEY.w:
            case cc.macro.KEY.s:
                this.vector.y = 0;
                break;
            case cc.macro.KEY.a:
            case cc.macro.KEY.d:
                this.vector.x = 0;
                break;
        }
    }


    update() {
        if (gameScene.is_pause) return;
        // 如果角色的移动向量为(0, 0)，就不执行以下代码
        if (this.vector.x == 0 && this.vector.y == 0) {
            return;
        }
        // 求出角色旋转的角度
        //let angle = this.vector_to_angle(this.vector);
        // 赋值给angle，Player脚本将会获取angle
        // this.angle = angle;
        let dis = this.vector.mag() / 100;
        let dir = this.vector.normalize();
        // 角色坐标加上方向
        let x = this.heroCtrl.node.position.x + dir.x * this.heroCtrl._speed * dis;
        let y = this.heroCtrl.node.position.y + dir.y * this.heroCtrl._speed * dis;
        if (y < -this._maxHeight) {
            y = -this._maxHeight;
        } else if (y > this._maxHeight) y = this._maxHeight;
        if (x < -this._maxWidth) {
            x = -this._maxWidth;
        } else if (x > this._maxWidth) x = this._maxWidth;
        // 设置角色坐标
        this.heroCtrl.node.setPosition(x, y);
        this.heroCtrl.setAngle(dir);
        mainCamera.setPos(cc.v2(x,y));
    }

    showJoyNode(pos) {
        // 将一个点转换到节点 (局部) 空间坐标系，这个坐标系以锚点为原点。
        pos = this.node.parent.convertToNodeSpaceAR(new cc.Vec3(pos.x, pos.y));
        this.node.setPosition(pos);
    }

    // 手指移动时调用，移动摇杆专用函数
    move(event: cc.Event.EventTouch) {
        // if(gameScene.is_pause)return;
        // 如果没有禁用摇杆
        if (this.is_forbidden == false) {
            /*
            通过点击屏幕获得的点的坐标是屏幕坐标
            必须先用相机从屏幕坐标转到世界坐标
            再从世界坐标转到节点坐标

            就这个问题折腾了很久
            踩坑踩坑踩坑
            */
            // 世界坐标转节点坐标
            // 将一个点转换到节点 (局部) 空间坐标系，这个坐标系以锚点为原点。
            let pos = this.parent.convertToNodeSpaceAR(event.getLocation());
            if (this._firstTouch) {
                this.showJoyNode(event.getLocation());
                this._firstTouch = false;
            }
            // 如果触点长度小于我们规定好的最大半径
            if (pos.len() < this.max_R) {
                // 摇杆的坐标为触点坐标
                this.joystick.setPosition(pos.x, pos.y);
                pos.normalizeSelf();
                this.vector = new cc.Vec2(pos.x * this.max_R, pos.y * this.max_R);
            } else {// 如果不

                // 将向量归一化
                pos.normalizeSelf();
                // 赋值给摇杆
                this.joystick.setPosition(pos.x * this.max_R, pos.y * this.max_R);
                this.vector = new cc.Vec2(this.joystick.position.x, this.joystick.position.y);
            }
        }
        // 如果摇杆被禁用 
        else {
            // 弹回摇杆
            this.finish();
        }
        this._firstTouch = false;

    }


    // 摇杆中心点弹回原位置专用函数
    finish() {
        // 摇杆坐标和移动向量都设为（0,0）
        this.joystick.position = new cc.Vec2(0, 0);
        this.vector = new cc.Vec2(0, 0);
        this.node.x = -cc.winSize.width/2 + 180;
        this.node.y = -cc.winSize.height/2 + 180;
        this._firstTouch = true;
    }



    // 角度转弧度
    angle_to_radian(angle: number): number {
        // 角度转弧度公式
        // π / 180 * 角度

        // 计算出弧度
        let radian = Math.PI / 180 * angle;
        // 返回弧度
        return (radian);
    }

    // 弧度转角度
    radian_to_angle(radian: number): number {
        // 弧度转角度公式
        // 180 / π * 弧度

        // 计算出角度
        let angle = 180 / Math.PI * radian;
        // 返回弧度
        return (angle);
    }

    // 角度转向量   
    angle_to_vector(angle: number): cc.Vec2 {
        // tan = sin / cos
        // 将传入的角度转为弧度
        let radian = this.angle_to_radian(angle);
        // 算出cos,sin和tan
        let cos = Math.cos(radian);// 邻边 / 斜边
        let sin = Math.sin(radian);// 对边 / 斜边
        // 结合在一起并归一化
        let vec = new cc.Vec2(cos, sin).normalize();
        // 返回向量
        return (vec);
    }

    // 向量转角度
    vector_to_angle(vector: cc.Vec2): number {
        // 将传入的向量归一化
        let dir = vector.normalize();
        // 计算出目标角度的弧度
        let radian = dir.signAngle(new cc.Vec2(1, 0));
        // 把弧度计算成角度
        let angle = -this.radian_to_angle(radian);
        // 返回角度
        return (angle);
    }


}